package com.yikome.promotion.service;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.yikome.common.CommonService;
import com.yikome.promotion.entity.Coupon;
import com.yikome.promotion.enums.CouponStatus;
import com.yikome.promotion.enums.FullReductionStatus;
import com.yikome.promotion.repository.CouponRepository;
import com.yikome.promotion.request.CouponRequest;
import com.yikome.promotion.response.CouponResponse;
import com.yikome.promotion.response.ShopCouponResponse;
import com.yikome.shop.entity.Shop;
import com.yikome.shop.repository.ShopRepository;
import com.yikome.utils.BeanUtils;
import com.yikome.utils.NamedParameterJdbcUtils;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;

@Service
public class CouponService extends CommonService<Coupon, Long> {

	@Autowired
	private CouponRepository couponRepository ;
	
	@Autowired
	private ShopRepository shopRepository ;
	
	@Autowired
	private NamedParameterJdbcTemplate jdbcTemplate ;
	
	public Page<CouponResponse> findCoupon(CouponRequest couponRequest, Pageable pageable) {
		
		//TODO 在这里作SQL更新处理
		Date nowTime = Calendar.getInstance(TimeZone.getTimeZone("+8")).getTime();
		String updateSQL = "UPDATE pro_coupon SET pro_coupon.status = :invalidStatus WHERE pro_coupon.yn = 1 AND pro_coupon.status <= :activeStatus AND pro_coupon.end_time <= :nowTime" ; 
		
		jdbcTemplate.update(updateSQL, ImmutableMap.of("invalidStatus", FullReductionStatus.INVALID.getStatus(), "activeStatus", FullReductionStatus.ACTIVE.getStatus(), "nowTime", nowTime));
		
		String contentSQL = "SELECT pro_coupon.* , s_shop.name shop_name \n" + 
							"FROM pro_coupon \n" + 
							"	LEFT JOIN s_shop ON (pro_coupon.shop_id = s_shop.id) \n" + 
							"WHERE pro_coupon.yn = 1 \n" ; 
		
		StringBuilder paramSQL = new StringBuilder("");
		Map<String , Object> paramMap = new HashMap<>();
		
		if(couponRequest.getShopId() != null) {
			paramSQL.append("AND pro_coupon.shop_id = :shopId \n");
			paramMap.put("shopId", couponRequest.getShopId());
		}
		if(couponRequest.getStatus() != null) {
			paramSQL.append("AND pro_coupon.status = :status \n");
			paramMap.put("status", couponRequest.getStatus());
		}
		if(StrUtil.isNotBlank(couponRequest.getPromotionName())) {
			paramSQL.append("AND pro_coupon.promotion_name like :promotionName \n");
			paramMap.put("promotionName", StrUtil.wrap(couponRequest.getPromotionName().trim(), "%"));
		}
		if(StrUtil.isNotBlank(couponRequest.getPromotionCode())) {
			paramSQL.append("AND pro_coupon.promotion_code like :promotionCode \n");
			paramMap.put("promotionCode", StrUtil.wrap(couponRequest.getPromotionCode().trim(), "%"));
		}
		
		String orderSQL = NamedParameterJdbcUtils.findOrderSQL(pageable);
    	String pageSQL = NamedParameterJdbcUtils.findPageSQL(pageable);
    	
    	List<CouponResponse> couponResponses = jdbcTemplate.query(contentSQL + paramSQL + orderSQL + pageSQL , paramMap, new BeanPropertyRowMapper<>(CouponResponse.class));
    	
    	for (CouponResponse couponResponse : couponResponses) {
    		couponResponse.setStatusName(FullReductionStatus.byStatus(couponResponse.getStatus()).getStatusName());
		}
    	
    	Long total = jdbcTemplate.queryForObject("SELECT COUNT(1) FROM (" + contentSQL + paramSQL + ") T", paramMap, Long.class);

        return new PageImpl<>(couponResponses, pageable, total);
	} 
	
	public List<CouponResponse> findShopCouponResponse(Long shopId) {
		
		Date nowTime = Calendar.getInstance(TimeZone.getTimeZone("+8")).getTime();
		
		String contentSQL = "SELECT pro_coupon.*, pro_coupon.id promotion_id FROM pro_coupon \n" + 
							"WHERE pro_coupon.yn = 1 \n" ; 
		
		StringBuilder paramSQL = new StringBuilder("");
		Map<String , Object> paramMap = new HashMap<>();
		
		paramSQL.append("AND pro_coupon.status = :status \n");
		paramMap.put("status", FullReductionStatus.ACTIVE.getStatus());
		
		paramSQL.append("AND pro_coupon.begain_time <= :nowTime AND pro_coupon.end_time > :nowTime \n");
		paramMap.put("nowTime", nowTime);
		
		paramSQL.append("AND pro_coupon.shop_id = :shopId \n");
		paramMap.put("shopId", shopId);
		
		String orderSQL = "ORDER BY pro_coupon.full_value ASC \n" ;
		
		return jdbcTemplate.query(contentSQL + paramSQL + orderSQL, paramMap, new BeanPropertyRowMapper<>(CouponResponse.class));
	}
	
	public ShopCouponResponse findShopCouponResponse(Long shopId, String promotionCode) {
		
		Date nowTime = Calendar.getInstance(TimeZone.getTimeZone("+8")).getTime();
		
		String contentSQL = "SELECT pro_coupon.*, pro_coupon.id promotion_id FROM pro_coupon \n" + 
							"WHERE pro_coupon.yn = 1 \n" ; 
		
		StringBuilder paramSQL = new StringBuilder("");
		Map<String , Object> paramMap = new HashMap<>();
		
		paramSQL.append("AND pro_coupon.status = :status \n");
		paramMap.put("status", CouponStatus.ACTIVE.getStatus());
		
		paramSQL.append("AND pro_coupon.begain_time <= :nowTime AND pro_coupon.end_time > :nowTime \n");
		paramMap.put("nowTime", nowTime);
		
		paramSQL.append("AND pro_coupon.shop_id = :shopId \n");
		paramMap.put("shopId", shopId);
		
		paramSQL.append("AND pro_coupon.promotion_code = :promotionCode \n");
		paramMap.put("promotionCode", promotionCode);
		
		String countSQL = "SELECT COUNT(1) FROM pro_coupon WHERE pro_coupon.yn = 1 \n" ;
		
		Long count = jdbcTemplate.queryForObject(countSQL + paramSQL, paramMap, Long.class);
		if(count == 0) return null ;
		
		return jdbcTemplate.queryForObject(contentSQL + paramSQL, paramMap, new BeanPropertyRowMapper<>(ShopCouponResponse.class));
	}

	@Transactional
	public Coupon persistCoupon(Coupon couponRequest) {
		
		Shop shop = shopRepository.findShop(couponRequest.getShopId());
		Preconditions.checkArgument(shop != null, "商城不存在...");
		
		if(couponRequest.getId() != null) {
			Coupon source = couponRepository.findCoupon(couponRequest.getId());
			
			Preconditions.checkArgument(source != null , "要修改的数据不存在...");
			Preconditions.checkArgument(source.getStatus() != CouponStatus.ACTIVE.getStatus(), "运行中的活动不允许修改...");
			
			BeanUtils.copyProperties(couponRequest, source, "id" , "status" , "yn");
			
			return couponRepository.save(source);
			
		}
		
		couponRequest.setStatus(CouponStatus.CREATE.getStatus());
		Coupon coupon = couponRepository.save(couponRequest);
		return coupon ;
	}
	
	@Transactional
	public void deleteCoupon(Long couponId) {
		
		Coupon coupon = couponRepository.findCoupon(couponId);
		Preconditions.checkArgument(coupon != null , "要删除的数据不存在...");
		
		Preconditions.checkArgument(coupon.getStatus() == CouponStatus.CREATE.getStatus(), "仅新增活动允许删除...");
		
		coupon.setYn(0);
		
		couponRepository.save(coupon) ; 
	}

	@Transactional
	public Coupon upFullCoupon(Long couponId) {
		
		Coupon coupon = couponRepository.findCoupon(couponId);
		Preconditions.checkArgument(coupon != null , "要删除的数据不存在...");
		
		Preconditions.checkArgument(coupon.getStatus() != CouponStatus.ACTIVE.getStatus(), "状态不允许删除...");
		
		coupon.setStatus(CouponStatus.ACTIVE.getStatus());
		
		return couponRepository.save(coupon) ; 
		
	}

	@Transactional
	public Coupon downCoupon(Long couponId) {

		Coupon coupon = couponRepository.findCoupon(couponId);
		Preconditions.checkArgument(coupon != null , "要删除的数据不存在...");
		
		Preconditions.checkArgument(coupon.getStatus() == CouponStatus.ACTIVE.getStatus(), "状态不允许删除...");
		
		coupon.setStatus(CouponStatus.INVALID.getStatus());
		
		return couponRepository.save(coupon) ; 
	}
}
